#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import json
import requests
import threading
from urllib.parse import quote
import time
import logging
import random

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('ncm_converter.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)

class NCMToWAVConverter:
    def __init__(self, music_dir, output_dir=None):
        self.music_dir = music_dir
        self.output_dir = output_dir or music_dir
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Referer': 'http://music.163.com/',
            'Cookie': 'appver=2.0.2'
        }
        
        # 确保输出目录存在
        if not os.path.exists(self.output_dir):
            os.makedirs(self.output_dir)
        
    def find_ncm_files(self):
        """查找目录下所有.ncm文件"""
        ncm_files = []
        for root, dirs, files in os.walk(self.music_dir):
            for file in files:
                if file.endswith('.ncm'):
                    ncm_files.append(os.path.join(root, file))
        return ncm_files
    
    def extract_song_info(self, ncm_file_path):
        """从.ncm文件名提取歌曲信息"""
        # 获取文件名（不含扩展名）
        filename = os.path.basename(ncm_file_path)
        song_info = filename.replace('.ncm', '')
        return song_info
    
    def search_wav_file(self, song_info):
        """搜索.wav格式的歌曲文件"""
        # 使用网易云音乐API搜索歌曲
        search_url = f"http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={quote(song_info)}&type=1&offset=0&total=true&limit=10"
        try:
            response = requests.get(search_url, headers=self.headers, timeout=10)

            if response.status_code == 200:
                data = response.json()
                logging.info(f'使用网易云音乐API搜索歌曲: {song_info}')
                if data.get('result') and data['result'].get('songs'):
                    # 返回第一首歌曲的ID
                    song_id = data['result']['songs'][0]['id']
                    # 获取歌曲下载链接
                    return self.get_song_download_url(song_id)
        except Exception as e:
            logging.error(f"搜索歌曲 {song_info} 时出错: {e}")
        return None
    
    def get_song_download_url(self, song_id):
        """获取歌曲下载链接"""
        # 使用网易云音乐的歌曲播放地址API
        # 这个API会返回歌曲的实际播放地址
        download_url = f"http://music.163.com/song/media/outer/url?id={song_id}"
        return download_url
    
    def download_wav_file(self, download_url, song_name):
        """下载音频文件"""
        if not download_url:
            logging.warning(f"下载链接为空: {song_name}")
            return False
            
        try:
            logging.info(f"开始下载: {song_name}")
            response = requests.get(download_url, headers=self.headers, timeout=30)
            if response.status_code == 200:
                # 检查返回内容是否为音频文件
                content_type = response.headers.get('Content-Type', '')
                content_length = response.headers.get('Content-Length', '0')
                
                logging.info(f"下载响应 Content-Type: {content_type}, Content-Length: {content_length}")
                
                # 检查是否是有效的音频文件
                if ('audio' in content_type or 'binary' in content_type) and int(content_length) > 10000:
                    # 根据Content-Type确定文件扩展名
                    if 'audio/mpeg' in content_type or 'audio/mp3' in content_type:
                        ext = '.mp3'
                    elif 'audio/x-wav' in content_type or 'audio/wav' in content_type:
                        ext = '.wav'
                    elif 'audio/flac' in content_type:
                        ext = '.flac'
                    else:
                        ext = '.mp3'  # 默认使用mp3格式
                    
                    output_path = os.path.join(self.output_dir, f"{song_name}{ext}")
                    with open(output_path, 'wb') as f:
                        f.write(response.content)
                    logging.info(f"成功下载: {song_name}{ext}")
                    return True
                else:
                    logging.warning(f"下载的文件可能不是有效的音频: {song_name}, Content-Type: {content_type}, Content-Length: {content_length}")
                    # 如果返回的是HTML内容，可能是错误页面
                    if 'text/html' in content_type:
                        logging.warning(f"可能遇到了API限制或需要认证")
                    return False
            else:
                logging.error(f"下载失败: {song_name}, 状态码: {response.status_code}")
        except requests.exceptions.Timeout:
            logging.error(f"下载超时: {song_name}")
        except requests.exceptions.ConnectionError:
            logging.error(f"连接错误: {song_name}")
        except Exception as e:
            logging.error(f"下载歌曲 {song_name} 时出错: {e}")
        return False
    
    def convert_ncm_to_wav(self, ncm_file_path):
        """将.ncm文件转换为音频文件"""
        try:
            # 从.ncm文件名提取歌曲信息
            song_info = self.extract_song_info(ncm_file_path)
            logging.info(f"正在处理: {song_info}")
            
            # 搜索音频文件
            download_url = self.search_wav_file(song_info)
            
            # 下载音频文件
            if download_url:
                return self.download_wav_file(download_url, song_info)
            else:
                logging.warning(f"未找到歌曲 {song_info} 的在线版本")
                return False
        except Exception as e:
            logging.error(f"处理文件 {ncm_file_path} 时出错: {e}")
            return False
    
    def process_all_files(self):
        """处理所有.ncm文件"""
        ncm_files = self.find_ncm_files()
        logging.info(f"找到 {len(ncm_files)} 个.ncm文件")
        
        if not ncm_files:
            logging.info("没有找到.ncm文件")
            return
            
        success_count = 0
        failed_count = 0
        
        for i, ncm_file in enumerate(ncm_files, 1):
            try:
                logging.info(f"进度: {i}/{len(ncm_files)}")
                if self.convert_ncm_to_wav(ncm_file):
                    success_count += 1
                else:
                    failed_count += 1
                    
                # 添加随机延迟避免请求过于频繁
                time.sleep(random.uniform(1, 3))
            except Exception as e:
                logging.error(f"处理文件 {ncm_file} 时出错: {e}")
                failed_count += 1
        
        logging.info(f"转换完成! 成功下载 {success_count} 个文件, 失败 {failed_count} 个")

def main():
    import argparse
    
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='将.ncm文件转换为音频文件')
    parser.add_argument('--music_dir', default='/Users/lijun/Library/Mobile Documents/com~apple~CloudDocs/Music', help='音乐文件目录')
    parser.add_argument('--output_dir', help='输出目录，默认为音乐文件目录')
    
    args = parser.parse_args()
    
    # 配置音乐目录
    music_dir = args.music_dir
    output_dir = args.output_dir
    
    # 检查音乐目录是否存在
    if not os.path.exists(music_dir):
        logging.error(f"音乐目录不存在: {music_dir}")
        return
    
    # 创建转换器实例
    converter = NCMToWAVConverter(music_dir, output_dir)
    
    # 处理所有文件
    converter.process_all_files()

if __name__ == "__main__":
    main()